package org.centsuse.intention_spring.invention.factory;

import lombok.Data;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.centsuse.intention_spring.invention.Exception.SceneLoadingException;
import org.centsuse.intention_spring.invention.config.scenes.SceneConfig;
import org.centsuse.intention_spring.invention.config.scenes.SceneConfiguration;
import org.centsuse.intention_spring.invention.config.scenes.processor.SceneProcessor;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * 处理器工厂类，根据配置默认加载处理器
 */
@Slf4j
@Data
@Component
public class SceneFactory implements ApplicationContextAware {

    private final SceneConfiguration sceneConfiguration;

    // 默认处理器
    private static final String DEFAULT_PROCESSOR_CLASS = "org.centsuse.intention_spring.invention.config.scenes.processor.CommonProcessor";

    // 处理器map
    private final Map<String, SceneProcessor> sceneProcessorMap = new HashMap<>();

    @Autowired
    private ApplicationContext applicationContext;

    public SceneFactory(SceneConfiguration sceneConfiguration) {
        this.sceneConfiguration = sceneConfiguration;
    }

    /**
     * @description 获取处理器实体
     * @param sceneName 场景名称
     * @return SceneProcessor
     */
    public SceneProcessor getProcessor(String sceneName) {
        return sceneProcessorMap.get(sceneName);
    }

    /**
     * @description 加载所有场景配置处理器
     * @throws SceneLoadingException
     */
    public void loadProcessors() throws SceneLoadingException {
        this.sceneProcessorMap.clear();
        log.info("[SceneFactory][loadSceneProcessor]Loading sceneConfiguration start, sceneConfiguration is {}", sceneConfiguration);
        Map<String, SceneConfig> configMap = this.sceneConfiguration.getSceneConfigMap();
        if (null == configMap || configMap.isEmpty()) {
            log.info("[SceneFactory][loadSceneProcessor]Loading sceneConfiguration end, sceneConfiguration: {}", sceneConfiguration);
        }
        // 加载processors
        for (Map.Entry<String, SceneConfig> entry : configMap.entrySet()) {
            loadSceneProcessor(entry.getValue());
        }
    }

    /**
     * 动态加载场景处理器SceneConfig
     *
     * @param config 场景配置
     */
    public void loadSceneProcessor(SceneConfig config)
            throws SceneLoadingException {
        log.info("[SceneFactory][loadSceneProcessor]Loading processor class start, config is {}", config);
        try {
            // 获取处理器类名（优先使用配置值）
            String className = Optional.ofNullable(config.getProcessorClass())
                    .filter(s -> !config.getProcessorClass().isEmpty())
                    .orElse(DEFAULT_PROCESSOR_CLASS);
            if (sceneProcessorMap.containsKey(className)) {
                return;
            }
            Class<?> clazz = Class.forName(className);
            validateProcessorClass(clazz);
            SceneProcessor sceneProcessor = (SceneProcessor) applicationContext.getBean(clazz);
            sceneProcessorMap.put(className, sceneProcessor);
            log.info("[SceneFactory][loadSceneProcessor]Loading processor class end, sceneProcessorMap is {}", sceneProcessorMap);
        } catch (ClassNotFoundException e) {
            throw new SceneLoadingException("处理器类未找到: " + config, e);
        } catch (Exception e) {
            throw new SceneLoadingException("处理器初始化失败", e);
        }
    }

    /**
     * @description 校验class是否实现了SceneProcessor接口
     * @param clazz
     */
    private void validateProcessorClass(Class<?> clazz) {
        if (!SceneProcessor.class.isAssignableFrom(clazz)) {
            throw new IllegalArgumentException("类必须实现SceneProcessor接口");
        }
    }
}
